﻿//using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;

public class Dic_Domain_Info : Standard_Info
{

    private string _Domain_Code;
    private string _Item_Code;
    private string _Item_Value;
    private string _Item_Order;

    private bool _Is_Active;
    public Dic_Domain_Info()
    {
    }


    public string Domain_Code
    {
        get { return _Domain_Code; }
        set { _Domain_Code = value; }
    }

    public string Item_Code
    {
        get { return _Item_Code; }
        set { _Item_Code = value; }
    }

    public string Item_Value
    {
        get { return _Item_Value; }
        set { _Item_Value = value; }
    }

    public string Item_Order
    {
        get { return _Item_Order; }
        set { _Item_Order = value; }
    }

    public bool Is_Active
    {
        get { return _Is_Active; }
        set { _Is_Active = value; }
    }
}

public class SystemController
{

    #region "Contructor"

    private static SystemController _instance;
    //// Note: Constructor is 'protected'
    protected SystemController()
    {
    }
    //// Note: Dispose is 'protected'
    protected void Dispose()
    {
        _instance = null;
    }
    //// Lock synchronization object
    private static object _syncLock = new object();
    // return the provider
    public static new SystemController Instance()
    {
        //// Support multithreaded applications through
        //// 'Double checked locking' pattern which (once
        //// the instance exists) avoids locking each
        //// time the method is invoked 
        if (_instance == null)
        {
            lock (_syncLock)
            {
                if (_instance == null)
                {
                    _instance = new SystemController();
                }
            }
        }
        //
        return _instance;
        //Return New UsersController
    }
    #endregion

    public void SysParam_ClearCache()
    {
        if ((m_dicSysParam != null))
            m_dicSysParam.Clear();
    }

    public void SysParam_Update(string sParamName, string sParamValue)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_SysParam_Update", sParamName.ToUpper(), sParamValue);
        if ((m_dicSysParam != null))
            m_dicSysParam.Remove(sParamName.ToUpper());
    }

    //Public Sub SysParam_Delete(ByVal sParamName As String)
    //    Domain_DeleteItem("SYSTEM_PARAM", sParamName)
    //End Sub

    public DataRowEx SysParam_SelectGroup(string sParamGroup)
    {
        return new DataRowEx(DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_SysParam_SelectGroup", sParamGroup.ToUpper()), "Param_Name", "Param_Value");
    }

    public void SysParam_Append(string sParamName, string sParamGroup, string sParamValue)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_SysParam_Append", sParamName.ToUpper(), sParamGroup, sParamValue);
    }

    private Dictionary<string, string> m_dicSysParam;
    public string SysParam_Select(string sParamName)
    {
        sParamName = sParamName.ToUpper();
        if (m_dicSysParam == null)
            m_dicSysParam = new Dictionary<string, string>();
        string retVal = null;
        if (!m_dicSysParam.ContainsKey(sParamName))
        {
            retVal = Globals.DB_GetString(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_SysParam_Select", sParamName.ToUpper()));
            if (!string.IsNullOrEmpty(retVal))
                m_dicSysParam.Add(sParamName, retVal);
        }
        else
        {
            retVal = m_dicSysParam[sParamName];
        }
        return retVal;
    }

    public T SysParam_Select<T>(string sParamName)
    {
        T objReturn = default(T);
        string sValue = SysParam_Select(sParamName);
        if (sValue == null)
        {
            return (T)Null.SetNullValue(objReturn);
        }
        else
        {
            if ((objReturn == null))
            {
                return (T)Globals.Object_SetValueEx(sValue, "String", false);
            }
            else
            {
                return (T)Globals.Object_SetValueEx(sValue, objReturn.GetType().Name, false);
            }
        }
    }

    public DateTime Sys_GetDate()
    {
        return Globals.Object_SetValueEx<DateTime>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Sys_GetDate"));
    }

    public void Domain_ClearCache()
    {
        if ((m_dicDomain != null))
            m_dicDomain.Clear();
    }

    private void Domain_RemoveCache(string sCode)
    {
        sCode = sCode.ToUpper();
        if ((m_dicDomain != null) && m_dicDomain.ContainsKey(sCode))
            m_dicDomain.Remove(sCode);
    }

    public System.DateTime Table_LastDDL(string sTableName)
    {
        //Purpose: 
        //   Lấy ngay cap nhat cau truc của 1 table
        //Parameters: 
        //   sTableName : tên bảng dữ liệu
        //Notes:
        //   Thường dùng khi cache cau truc cua bang dung de SetFormField
        return Globals.DB_GetValue(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_LastDDL", sTableName.ToUpper()), Null.MIN_DATE);
    }

    public DataTable Table_GetField(string sTableName)
    {
        return DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Table_GetField", sTableName.ToUpper());
    }

    public DataTable Table_List()
    {
        return DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Table_List");
    }

    public DataTable Table_Structure(string sTableName)
    {
        return DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Table_Structure", sTableName);
    }

    public string Table_KeyColumn(string sTableName, string sKey)
    {
        return Globals.DB_GetString(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_KeyColumn", sTableName.ToUpper(), sKey));
    }

    public bool Table_Deletable(string sTableName, object sPKValue)
    {
        //Purpose: 
        //   Kiểm tra 1 dòng của bảng có được phép xóa hay không
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng để kiểm tra trước khi xóa 1 dòng dữ liệu của các bảng Dictionary
        //   nếu k được phép xóa sẽ phải chuyển sang trạng thái Is_Active=0
        return Globals.Object_GetValue<Boolean>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_Deletable", sTableName.ToUpper(), sPKValue.ToString()));
    }

    public bool Table_ExistValue(string sTableName, object iPKValue)
    {
        return Table_ExistValue(sTableName, null, iPKValue, null);
    }

    public bool Table_ExistValue(string sTableName, string sFieldName, object iPKValue, object sValue)
    {
        //Purpose: 
        //   Kiểm tra giá trị của 1 field đã tồn tại hay không
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên field cần lấy kiểm tra
        //   iPKValue    : giá trị của PK
        //   sValue      : giá trị cần kiểm tra
        //Return:
        //   True        : đã tồn tại giá trị
        //   False       : chưa tồn tại giá trị 
        //Notes:
        //   Thường dùng khi kiểm tra không cho phép nhập trùng Code
        return ( Globals.Object_GetValue<Int32>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_CheckValue", sTableName.ToUpper(), sFieldName, iPKValue, sValue)) > 0);
    }

    public string Table_GetValue(string sTableName, string sFieldName, object iPKValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 field hoặc 1 tổ hợp của nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên field cần lấy dữ liệu
        //   iPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua ID
        return Globals.DB_GetString(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_GetValue", sTableName.ToUpper(), sFieldName, iPKValue));
    }

    public T Table_GetValue<T>(string sTableName, string sFieldName, object iPKValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 field hoặc 1 tổ hợp của nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên field cần lấy dữ liệu
        //   iPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua ID
        return Globals.DB_GetValue<T>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_GetValue", sTableName.ToUpper(), sFieldName, iPKValue));
    }

    public T Table_GetValue<T>(string sTableName, string sFieldSelect, string sFieldName, object oValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 hoặc nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên các field cần lấy dữ liệu (ngăn cách bằng dấu phẩy)
        //   iPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua ID
        return Globals.DB_GetValue<T>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_GetRow", sTableName.ToUpper(), sFieldSelect, sFieldName, oValue));
    }

    public DataRowEx Table_GetRow(string sTableName, string sFieldName, object iPKValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 hoặc nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên các field cần lấy dữ liệu (ngăn cách bằng dấu phẩy)
        //   iPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua ID
        return DataConnect.ExecuteRow(DataConnect.WorkingConnect, "App_Table_GetValue", sTableName.ToUpper(), sFieldName, iPKValue);
    }

    public DataRowEx Table_GetRow(string sTableName, string sFieldSelect, string sFieldName, object oValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 hoặc nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên các field cần lấy dữ liệu (ngăn cách bằng dấu phẩy)
        //   iPKValue    : giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua ID
        return DataConnect.ExecuteRow(DataConnect.WorkingConnect, "App_Table_GetRow", sTableName.ToUpper(), sFieldSelect, sFieldName, oValue);
    }

    public string Table_GetValues(string sTableName, string sFieldName, string sPKValue)
    {
        //Purpose: 
        //   Lấy giá trị của 1 field hoặc 1 tổ hợp của nhiều field theo giá trị của PK
        //Parameters: 
        //   sTableName  : tên bảng dữ liệu
        //   sFieldName  : tên field cần lấy dữ liệu
        //   sPKValue    : các giá trị của PK
        //Notes:
        //   Thường dùng khi lấy các giá trị Name thông qua nhiều ID
        if (sPKValue.Contains(";"))
            sPKValue = sPKValue.Replace(";", ",");
        return Globals.Object_GetValue<string>(Globals.DB_GetValue(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Table_GetValues", sTableName.ToUpper(), sFieldName, sPKValue), null));
    }


    private Dictionary<string, DataTable> m_dicDomain;
    public string Domain_GetValue(string sDomain, string sItemCode)
    {
        //Purpose: 
        //   Lấy các giá trị của 1 Domain Item trong bảng App_Dic_Domain
        //Parameters: 
        //   sDomain     : tên của Domain
        //   sItemCode   : ma Item
        //Notes:
        //   Lay gia tri tu DB va khong luu lai
        return Globals.Object_GetValue<string>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Domain_GetValue", sDomain, sItemCode));
    }

    public DataTable Domain_GetDic(string sDomain)
    {
        //Purpose: 
        //   Lấy các giá trị của 1 Domain trong bảng App_Dic_Domain
        //Parameters: 
        //   sDomain     : tên của Domain
        //Notes:
        //   - Bảng App_Dic_Domain chứa các tập hợp giá trị dạng Item_Code,Item_Value
        //   các tập hợp được phân biệt bằng tên Domain (Domain_Code)
        //   - DataTable trả về sẽ được lưu lại trong Dictionary để reuse, 
        //   do đó các giá trị lưu trong bảng App_Dic_Domain là các giá trị gần như không thay đổi
        return Domain_GetDic(sDomain, false);
    }

    private DataTable Domain_GetDic(string sDomain, bool bReadOnly)
    {
        //Purpose: 
        //   Hàm private để lấy các giá trị của 1 Domain trong bảng App_Dic_Domain
        //   Trong trường hợp ReadOnly sẽ lấy thẳng giá trị trong Dictionary mà không qua bước Copy 
        //
        sDomain = sDomain.ToUpper();
        if (m_dicDomain == null)
        {
            m_dicDomain = new Dictionary<string, DataTable>();
        }
        DataTable dtReturn = default(DataTable);
        if (m_dicDomain.ContainsKey(sDomain))
        {
            dtReturn = m_dicDomain[sDomain];
        }
        else
        {
            dtReturn = DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Domain_GetDic", sDomain);
            //
            dtReturn.PrimaryKey = new DataColumn[] { dtReturn.Columns["Item_Code"] };
            dtReturn.AcceptChanges();
            //
            m_dicDomain.Add(sDomain, dtReturn);
        }
        if (bReadOnly)
        {
            return dtReturn;
        }
        else
        {
            return dtReturn.Copy();
        }
    }

    public string Domain_GetItemCode(string sDomain, int iIndex)
    {
        //Purpose: 
        //   Lấy giá trị Item_Code của 1 Domain trong bảng App_Dic_Domain theo Index
        //Parameters: 
        //   sDomain     : tên của Domain
        //   iIndex      : index của Item
        //Notes:
        //   Item trong được sort theo field Order_Code trong bảng App_Dic_Domain
        DataTable dt = Domain_GetDic(sDomain, true);
        if (iIndex < dt.Rows.Count)
        {
            return Globals.Object_GetValue<string>(dt.Rows[iIndex][0]);
        }
        else
        {
            throw new Exception(string.Format("Item with index {0} not found in dic '{1}'", iIndex, sDomain));
        }
    }

    public string Domain_GetItemValue(string sDomain, int iIndex)
    {
        //Purpose: 
        //   Lấy giá trị Item_Value của 1 Domain trong bảng App_Dic_Domain theo Index
        //Parameters: 
        //   sDomain     : tên của Domain
        //   iIndex      : index của Item
        //Notes:
        //   Item trong được sort theo field Order_Code trong bảng App_Dic_Domain
        DataTable dt = Domain_GetDic(sDomain, true);
        if (iIndex < dt.Rows.Count)
        {
            return Globals.Object_GetValue<string>(dt.Rows[iIndex][1]);
        }
        else
        {
            throw new Exception(string.Format("Item with index {0} not found in dic '{1}'", iIndex, sDomain));
        }
    }

    public string Domain_GetItemValue(string sDomain, string sCode)
    {
        //Purpose: 
        //   Lấy giá trị Item_Value của 1 Domain trong bảng App_Dic_Domain theo Item_Code
        //Parameters: 
        //   sDomain     : tên của Domain
        //   sCode       : giá trị của Item_Code
        //Notes:
        //   
        return Domain_GetItemValue(sDomain, sCode, null);
    }

    public string Domain_GetItemValue(string sDomain, string sCode, string sDefault)
    {
        DataTable dt = Domain_GetDic(sDomain, true);
        DataRow dr = dt.Rows.Find(sCode);
        if ((dr != null))
        {
            return Globals.Object_GetValue<string>(dr[1]);
        }
        else
        {
            if (sDefault == null)
            {
                throw new Exception(string.Format("Item with code {0} not found in dic '{1}'", sCode, sDomain));
            }
            else
            {
                return sDefault;
            }
        }
    }

    public DataRowEx Domain_GetItem(string sDomain, string sCode)
    {
        DataTable dt = Domain_GetDic(sDomain, true);
        DataRow dr = dt.Rows.Find(sCode);
        if ((dr != null))
        {
            return new DataRowEx(dr);
        }
        else
        {
            return null;
        }
    }

    public DataTable Domain_ListDic()
    {
        return DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Domain_ListDic");
    }

    public bool Domain_ExistDic(string sDicCode)
    {
        return ( Globals.Object_GetValue<Int32>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Domain_ExistDic", sDicCode.ToUpper())) != 0);
    }

    public void Domain_InsertDic(string sDicCode, string sDicName, bool isActive)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_InsertDic", sDicCode.ToUpper(), sDicName, isActive);
    }

    public void Domain_UpdateDic(string sDicCode, string sDicName, bool isActive)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_UpdateDic", sDicCode.ToUpper(), sDicName, isActive);
    }

    public Dic_Domain_Info Domain_SelectDic(string sDicCode)
    {
        return CBO.FillObject<Dic_Domain_Info>(DataConnect.ExecuteRow(DataConnect.WorkingConnect, "App_Domain_SelectDic", sDicCode.ToUpper()));
    }

    public void Domain_DeleteDic(string sDicCode)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_DeleteDic", sDicCode);
    }

    public DataTable Domain_ListItem(string sDicCode)
    {
        return Domain_ListItem(sDicCode, "");
    }

    public DataTable Domain_ListItem(string sDicCode, string sCodeList)
    {
        return DataConnect.ExecuteTable(DataConnect.WorkingConnect, "App_Domain_ListItem", sDicCode.ToUpper(), sCodeList.ToUpper());
    }

    public bool Domain_ExistItem(string sDicCode, string sItemCode)
    {
        return ( Globals.Object_GetValue<Int32>( DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Domain_ExistItem", sDicCode, sItemCode)) != 0);
    }

    public string Domain_InsertItem(string sDicCode, string sItemCode, string sItemValue, short sItemOrder, bool bIsActive)
    {
        if (string.IsNullOrEmpty(sItemCode))
        {
            sItemCode = new Guid().ToString();
            //automatic assign guid value
        }
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_InsertItem", sDicCode.ToUpper(), sItemCode.ToUpper(), sItemValue, Globals.DB_GetNull(sItemOrder), bIsActive);
        //
        Domain_RemoveCache(sDicCode);
        //
        return sItemCode;
    }

    public void Domain_UpdateItem(string sDicCode, string sItemCode, string sItemValue, short sItemOrder, bool bIsActive)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_UpdateItem", sDicCode.ToUpper(), sItemCode.ToUpper(), sItemValue,Globals.DB_GetNull(sItemOrder), bIsActive);
        //
        Domain_RemoveCache(sDicCode);
    }

    public void Domain_AppendItem(string sDicCode, string sItemCode, string sItemValue)
    {
        Domain_AppendItem(sDicCode, sItemCode, sItemValue, Null.NullShort, true);
    }

    public void Domain_AppendItem(string sDicCode, string sItemCode, string sItemValue, short sItemOrder, bool bIsActive)
    {
        if (string.IsNullOrEmpty(sItemCode))
        {
            sItemCode = new Guid().ToString();
            //automatic assign guid value
        }
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_AppendItem", sDicCode.ToUpper(), sItemCode.ToUpper(), sItemValue, Globals.DB_GetNull(sItemOrder), bIsActive);
        //
        Domain_RemoveCache(sDicCode);
    }

    public Dic_Domain_Info Domain_SelectItem(string sDicCode, string sItemCode)
    {
        return CBO.FillObject<Dic_Domain_Info>(DataConnect.ExecuteRow(DataConnect.WorkingConnect, "App_Domain_SelectItem", sDicCode.ToUpper(), sItemCode.ToUpper()));
    }

    public void Domain_DeleteItem(string sDicCode, string sItemCode)
    {
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Domain_DeleteItem", sDicCode.ToUpper(), sItemCode.ToUpper());
        //
        Domain_RemoveCache(sDicCode);
        //'
    }

    public bool Domain_Deletable(string sDicCode, string sItemCode)
    {
        return Globals.Object_GetValue<Int32>(DataConnect.ExecuteScalar(DataConnect.WorkingConnect, "App_Domain_Deletable", sDicCode.ToUpper(), sItemCode.ToUpper())) == 1;
    }

    public string Default_GetValue(string sName)
    {
        //Purpose: 
        //   Lấy giá trị mặc định của 1 field 
        //Parameters: 
        //   sName     : tên field
        //Notes:
        //   Các giá trị mặc định được lưu trong Domain 'DEFAULT_VALUE' của bảng App_Dic_Domain
        //   
        DataTable dt = Domain_GetDic("DEFAULT_VALUE");
        DataRow dtRow = dt.Rows.Find(sName);
        if (dtRow == null)
        {
            return null;
        }
        else
        {
            return Globals.Object_GetValue<string>(dtRow[1]);
        }
    }

    public DataRowEx Default_GetTable(string sTableName)
    {
        //Purpose: 
        //   Lấy giá trị mặc định của 1 table 
        //Parameters: 
        //   sName     : tên field
        //Notes:
        //   Các giá trị mặc định được lưu trong Domain 'SYS.TABLENAME' của bảng App_Dic_Domain
        //   
        DataTable dt = Domain_GetDic("DEFAULT." + sTableName.ToUpper());
        return new DataRowEx(dt, "Item_Code", "Item_Value");
    }

    public void Error_Insert(string sClientIP, string sEnvironment, string sUser, string sFunction, Exception ex)
    {
        //Purpose: 
        //   Ghi lỗi
        //Parameters: 
        //   
        //Notes:
        //   
        //   
        DataConnect.ExecuteNonQuery(DataConnect.WorkingConnect, "App_Error_Insert", sClientIP, sEnvironment, sUser, sFunction, ex.Message, ex.Source, ex.StackTrace);
    }
}
